package gui.product;

import java.util.Date;
import java.util.Observable;
import java.util.Observer;

import gui.common.*;
import hit.core.Barcode;
import hit.core.HomeInventoryTracker;
import hit.core.Product;
import hit.core.ProductFacade;
import hit.core.Size;
import hit.core.Size.Unit;
import hit.dao.DataAccessObject;
import hit.dao.FactoryReference;
import hit.util.SizeConverter;
import hit.util.autoProductID.PIThread;

/**
 * Controller class for the add item view.
 */
public class AddProductController extends Controller implements
		IAddProductController, Observer {
	
	ProductFacade facade;
	
	String barcode;
	String description;
	Size size;
	int shelfLife;
	int threeMonth;
	
	/**
	 * Constructor.
	 * 
	 * @param view Reference to the add product view
	 * @param barcode Barcode for the product being added
	 */
	public AddProductController(IView view, String barcode) {
		super(view);
		
		facade = HomeInventoryTracker.Instance().GetProductFacade();
		
		this.barcode = barcode;
		description = "";
		size = new Size(1, Size.Unit.COUNT);
		shelfLife = 0;
		threeMonth = 0;
		
		construct();
		
		PIThread piThread = new PIThread(barcode);
		piThread.addObserver(this);
		
		Thread thread = new Thread(piThread, "PIThread");
		thread.start();
	}

	//
	// Controller overrides
	//
	
	/**
	 * Returns a reference to the view for this controller.
	 * 
	 * {@pre None}
	 * 
	 * {@post Returns a reference to the view for this controller.}
	 */
	@Override
	protected IAddProductView getView() {
		return (IAddProductView)super.getView();
	}

	/**
	 * Sets the enable/disable state of all components in the controller's view.
	 * A component should be enabled only if the user is currently
	 * allowed to interact with that component.
	 * 
	 * {@pre None}
	 * 
	 * {@post The enable/disable state of all components in the controller's view
	 * have been set appropriately.}
	 */
	@Override
	protected void enableComponents() {
		
		getView().enableBarcode(false);
		getView().enableDescription(false);
		getView().enableShelfLife(false);
		getView().enableSizeUnit(false);
		getView().enableSizeValue(false);
		getView().enableSupply(false);
		
		getView().enableOK(false);
		
		getView().setDescription("Retrieving Description - Please Wait...");
	}

	/**
	 * Loads data into the controller's view.
	 * 
	 *  {@pre None}
	 *  
	 *  {@post The controller has loaded data into its view}
	 */
	@Override
	protected void loadValues() {
		
		getView().setBarcode(barcode);
		getView().setDescription(description);
		getView().setShelfLife(Integer.toString(shelfLife));
		getView().setSupply(Integer.toString(threeMonth));
		getView().setSizeValue(Double.toString(size.GetAmount()));
		getView().setSizeUnit(SizeConverter.ConvertModelUnitsToController(size.GetType()));
	}

	//
	// IAddProductController overrides
	//
	
	/**
	 * This method is called when any of the fields in the
	 * add product view is changed by the user.
	 */
	@Override
	public void valuesChanged() {
		
		description = getView().getDescription();
		
		SizeUnits sizeUnit = getView().getSizeUnit();
		
		try {			
			if (sizeUnit == SizeUnits.Count)
			{
				getView().setSizeValue("1");
				getView().enableSizeValue(false);
			}
			else
			{
				getView().enableSizeValue(true);
			}
		
			double sizeAmount = Double.parseDouble(getView().getSizeValue());
			size = new Size(sizeAmount, SizeConverter.ConvertControllerUnitsToModel(sizeUnit));
			
			shelfLife = Integer.parseInt(getView().getShelfLife());
			threeMonth = Integer.parseInt(getView().getSupply());
			
			Product newProduct = new Product();
			newProduct.SetCreation(new Date());
			newProduct.SetBarcode(new Barcode(barcode));
			newProduct.SetDescription(description);
			newProduct.SetShelfLife(shelfLife);
			newProduct.SetThreeMonth(threeMonth);
			newProduct.SetSize(size);
			
			getView().enableOK(facade.CanAddProduct(newProduct));
		}
		catch (Exception e) {
			description = "";
			size = null;
			shelfLife = -1;
			threeMonth = -1;
			getView().enableOK(false);
		}
	}
	
	/**
	 * This method is called when the user clicks the "OK"
	 * button in the add product view.
	 */
	@Override
	public void addProduct() {
		try {
			Product newProduct = new Product();
			newProduct.SetCreation(new Date());
			newProduct.SetBarcode(new Barcode(barcode));
			newProduct.SetDescription(description);
			newProduct.SetShelfLife(shelfLife);
			newProduct.SetThreeMonth(threeMonth);
			newProduct.SetSize(size);
			
			facade.AddProduct(newProduct);
			
			DataAccessObject dao = FactoryReference.GetFactory().CreateDataAccessObject();
			
			dao.StartTransaction();
			
			int id = dao.GetProductDAO().Create(newProduct);
			newProduct.setId(id);
			
			dao.EndTransaction(true);
			
			dao.CloseConnection();
		}
		catch (Exception e) {
			e.printStackTrace();
			getView().displayErrorMessage("Failed to Create Product.");
		}
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		
		String result = (String)arg1;
		
		getView().setDescription(result);
		description = result;
		
		getView().enableDescription(true);
		getView().enableShelfLife(true);
		getView().enableSizeUnit(true);
		getView().enableSupply(true);
		
		getView().enableOK(description != null && !description.equals(""));
	}

}

